import backtrader as bt
import numpy as np
import pandas as pd
import traceback

from indicators.KeyPointsInd import KeyPointsInd
from indicators.bias_ind import bias_ind
from indicators.wave_index_ind import wave_index_ind


class KeyPointsStrategy(bt.Strategy):
    # 策略参数
    params = dict(
        period=20,  # 均线周期
        look_back_days=30,
        printlog=False,
        period_ema_fast=10,
        period_ema_slow=100,
        short_window=20,
        long_window=60,
        N1=3,
        N2=50,
        N3=25,
        key_window=25,
        wave_two_window=50,
        wave_three_window=70,
        distance=50,
        prominence=2
    )
    def __init__(self):
        try:
         for data in self.datas:
           data.stockdata = KeyPointsInd().getwave(distance=self.p.distance,prominence=self.p.prominence, data=data,show=True,ago=None,size=None)
           data.resistance_val=0
           data.resistance_val_list=[]
           data.resistance_buy = 0  # 突破买入点
           data.resistance_sell = 0  # 跌破卖出点
           data.profit_sell = 0 #盈利卖出
           data.resistance_val = 0 # 阻力点
           data.resistance_len =0 # 阻力点发生的位置
           data.resistance_h_and_l=0 #高点地点相加作为标识符使用
           data.short_ma = bt.indicators.SMA(data.close, period=self.p.short_window)
           data.profit = 0
           data.resistance_h=0#阻力
           data.resistance_h_ind=0
           data.resistance_bili = 0#最小比例值

           data.resistance_sell_order=0#已生成订单的止损点
           data.profit_sell_order = 0  # 已生成订单的盈利卖出

           data.profit_h_order = 0  # 订单中的高点
           data.order_price=0#订单买入价
           data.order_num = 0  # 买入次数
           data.bias24 = bias_ind(wave_window=25, data=data.close)
           #for A, B in zip(stockdata['val'], stockdata['ind']):
           #    print(A, B)
           #print(KeyPointsInd)



        except Exception as e:
            traceback.print_exc()

        #遍历所有股票,计算20日均线
        #for data in self.datas:

    def notify_order(self, order):
        """
        订单状态处理

        Arguments:
            order {object} -- 订单状态
        """
        if order.status in [order.Submitted, order.Accepted]:
            # 如订单已被处理，则不用做任何事情
            return

        # 检查订单是否完成
        if order.status in [order.Completed]:
            if order.isbuy():
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
                #print('BUY成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
            #elif order.issell():
                #print('SELL成交, 执行价={0}, {1}'.format(order.executed.price, order.executed.size))
            self.bar_executed = len(self)
        # 订单因为缺少资金之类的原因被拒绝执行
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
        # 订单状态处理完成，设为空
        self.order = None

    def notify_trade(self, trade):
        """
        交易成果

        Arguments:
            trade {object} -- 交易状态
        """
        if not trade.isclosed:
            return

        # 显示交易的毛利率和净利润
        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm), doprint=True)

    def next(self):
        total_value = self.broker.getvalue()
        p_value = total_value*0.9/10
        for data in self.datas:


            pos = self.getposition(data).size
            stockdata = data.stockdata
            #print(len(data))
            h = self.getKeyNum(stockdata, len(data), 1) # 前高点



            if h is not None and not pos:
               l = self.getKeyNum(stockdata, h.ind, 2)  # 前高点
               if l is not None:
                 resistance = (h.val - l.val) / l.val
                 bili = int(resistance+1)*2
                 if bili == 0 :
                     continue
                 #最小分数
                 bili=(resistance/bili)/2
                 if bili <0.1:
                     continue
                 #resistance_val=h.val -(h.val * bili)
                 #阻力高低点随时间轴变换
                 if data.resistance_h_and_l !=0 and data.resistance_h_and_l != (h.val + l.val) and not pos:
                     data.resistance_val = 0
                     data.resistance_buy = 0  # 突破买入点
                     data.resistance_sell = 0  # 跌破卖出点
                     data.profit_sell = 0  # 盈利卖出
                     data.resistance_val = 0  # 阻力点
                     data.resistance_len = 0  # 阻力点发生的位置
                     data.resistance_h_and_l = 0  # 高点地点相加作为标识符使用
                     data.profit = 0
                     data.resistance_h = 0  # 阻力
                     data.resistance_h_ind = 0
                     data.resistance_bili = 0  # 最小比例值
                     data.resistance_sell_order = 0  # 已生成订单的止损点
                     data.profit_sell_order = 0  # 已生成订单的盈利卖出
                     data.profit_h_order = 0  # 订单中的高点
                     data.order_price = 0  # 订单买入价
                     data.order_num = 0  # 买入次数

                 for i in range(2, 4):
                     resistance_val = h.val - (h.val * bili*i)#关键线
                     #判断阻力线是否已被触及，当前及之前
                     if data.resistance_val==resistance_val  or resistance_val  in data.resistance_val_list \
                             or ((h.val +l.val)==data.resistance_h_and_l and data.resistance_val<resistance_val):
                         continue
                     if data.high[0] > resistance_val and data.low[0] < resistance_val:
                             data.resistance_buy=data.high[0]
                                 #(resistance_val*bili*0.75)+resistance_val
                             data.resistance_h =data.high[0]
                             data.resistance_h_ind = h.ind
                             data.resistance_bili=bili
                                 #data.high[0]  #突破买入点
                             data.resistance_sell =data.low[0]
                                 #resistance_val- (resistance_val*bili)
                                 #data.low[0]  # 跌破卖出点
                             data.profit_sell=(resistance_val*bili*2)+resistance_val
                             data.resistance_val = resistance_val#写入回测数据众
                             data.resistance_len = len(data)#阻力点发生的位置
                             data.order_num = 0  # 买入次数
                             data.resistance_h_and_l = h.val +l.val # 阻力数据相加，作为标识符

                         #print(len(data))
            #pos = self.getposition(data).size
            #data.close[0] > data.N_High[0] and
            if not pos :
                if data.low[0] < data.resistance_val and data.resistance_val !=0 :
                    #print((data.resistance_val - data.low[0]))
                    #print(data.resistance_bili)
                    d1=(data.resistance_val - data.low[0])/data.resistance_val
                    d2=data.resistance_bili*10
                    if d1> d2:
                       data.resistance_val_list.append(data.resistance_val)
                if len(data) - data.resistance_h_ind >300:
                       data.resistance_val_list.append(data.resistance_val)


                #print(data.resistance_buy,data.resistance_len)
                #and  data.high[0]  > data.resistance_buy  and data.close[0] >data.open[0]
                #and len(data)- data.resistance_len<8
                if data.high[0]  > data.resistance_buy  and len(data)- data.resistance_h_ind>8  and data.close[0]>data.resistance_h and  data.resistance_buy !=0  and len(data)- data.resistance_len>0 \
                        and data.resistance_val  not in data.resistance_val_list :
                            if data.order_num >=2:
                                continue
                            data.order_num = data.order_num+1
                            print(data._name,'',data.datetime.date(0))
                            print(data.resistance_buy, data.resistance_len,len(data),data.resistance_h_and_l)
                            self.order = self.buy ( data=data )
                            data.order_price=data.close[0]
                            #data.resistance_val_list.append(data.resistance_val)

            if pos!=0 :
                #上升过程中点位监控
                self.getResistance_sell_order(data)
                if data.order_price!=0 and data.close[0] -data.order_price >0:#已盈利
                    if (data.high[0] - data.order_price)/data.order_price >0.05 :#盈利5个点
                        data.profit_h_order = data.high[0]
                if   data.profit_h_order != 0 and (data.close[0] - data.order_price)/data.order_price <0.02:
                        self.close ( data = data )
                        data.profit_h_order=0
                        data.order_price = 0
                        data.resistance_sell_order=0
                        #or data.high[0] < data.short_ma[0]
                elif  data.close[0] <data.resistance_sell or data.high[0] >=data.profit_sell or ( data.close[0] < data.resistance_sell_order ):
                    data.profit = 0
                    self.close ( data = data )
                    data.profit_h_order = 0
                    data.order_price = 0
                    data.resistance_sell_order=0
    def log(self, txt, dt=None,doprint=False):
        if self.params.printlog or doprint:
            dt = dt or self.datas[0].datetime.date(0)
            print(f'{dt.isoformat()},{txt}')
    #  or self.getFrontB( data, 3) == True
    def getFrontB(self, data,  end):
        for i in range(1, end):
            if data.close[-i] > data.close[-(i+1)]:
                return False
        return True
    #冒泡查询
    def getKeyNum(self, stockdata, indNum,dataType):
        data=None
        for row in stockdata.itertuples():
            ind = row.ind
            type =row.type
            if type == dataType and indNum > ind :
                data = row
                break
        return data

    #
    def getResistance_sell_order(self, data):
        bili = data.resistance_bili
        close= data.close[0]
        low= data.low[0]
        resistance_val=data.resistance_val
        for i in range(1, 20):
            d = resistance_val+(resistance_val*bili*i)
            if low > d:
                data.resistance_sell_order = d  # 已生成订单的止损点











    #记录交易收益情况（可省略，默认不输出结果）
    #def notify_trade(self,trade):
    #    if not trade.isclosed:
    #        return
    #    self.log(f'策略收益：\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')
